// SPDX-License-Identifier: Apache-2.0
//===-- ssvm/common/ast.h - AST enumeration definition --------------------===//
//
// Part of the SSVM Project.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file contains the enumerations of Wasm VM used AST and instruction
/// nodes enumerations.
///
//===----------------------------------------------------------------------===//
#pragma once

#include <cstdint>
#include <string>
#include <unordered_map>

namespace SSVM {

/// AST node attributes enumeration class.
enum class ASTNodeAttr : uint8_t {
  Module,
  Sec_Custom,
  Sec_Type,
  Sec_Import,
  Sec_Function,
  Sec_Table,
  Sec_Memory,
  Sec_Global,
  Sec_Export,
  Sec_Start,
  Sec_Element,
  Sec_Code,
  Sec_Data,
  Desc_Import,
  Desc_Export,
  Seg_Global,
  Seg_Element,
  Seg_Code,
  Seg_Data,
  Type_Function,
  Type_Limit,
  Type_Memory,
  Type_Table,
  Type_Global,
  Expression,
  Instruction
};

/// AST node attributes enumeration string mapping.
static inline std::unordered_map<ASTNodeAttr, std::string> ASTNodeAttrStr = {
    {ASTNodeAttr::Module, "module"},
    {ASTNodeAttr::Sec_Custom, "custom section"},
    {ASTNodeAttr::Sec_Type, "type section"},
    {ASTNodeAttr::Sec_Import, "import section"},
    {ASTNodeAttr::Sec_Function, "function section"},
    {ASTNodeAttr::Sec_Table, "table section"},
    {ASTNodeAttr::Sec_Memory, "memory section"},
    {ASTNodeAttr::Sec_Global, "global section"},
    {ASTNodeAttr::Sec_Export, "export section"},
    {ASTNodeAttr::Sec_Start, "start section"},
    {ASTNodeAttr::Sec_Element, "element section"},
    {ASTNodeAttr::Sec_Code, "code section"},
    {ASTNodeAttr::Sec_Data, "data section"},
    {ASTNodeAttr::Desc_Import, "import description"},
    {ASTNodeAttr::Desc_Export, "export description"},
    {ASTNodeAttr::Seg_Global, "global segment"},
    {ASTNodeAttr::Seg_Element, "element segment"},
    {ASTNodeAttr::Seg_Code, "code segment"},
    {ASTNodeAttr::Seg_Data, "data segment"},
    {ASTNodeAttr::Type_Function, "function type"},
    {ASTNodeAttr::Type_Limit, "limit"},
    {ASTNodeAttr::Type_Memory, "memory type"},
    {ASTNodeAttr::Type_Table, "table type"},
    {ASTNodeAttr::Type_Global, "global type"},
    {ASTNodeAttr::Expression, "expression"},
    {ASTNodeAttr::Instruction, "instruction"}};

/// Instruction opcode enumeration class.
enum class OpCode : uint16_t {
  /// Control instructions
  Unreachable = 0x00,
  Nop = 0x01,
  Block = 0x02,
  Loop = 0x03,
  If = 0x04,
  Else = 0x05,
  End = 0x0B,
  Br = 0x0C,
  Br_if = 0x0D,
  Br_table = 0x0E,
  Return = 0x0F,
  Call = 0x10,
  Call_indirect = 0x11,

  /// Parametric Instructions
  Drop = 0x1A,
  Select = 0x1B,

  /// Variable Instructions
  Local__get = 0x20,
  Local__set = 0x21,
  Local__tee = 0x22,
  Global__get = 0x23,
  Global__set = 0x24,

  /// Memory Instructions
  I32__load = 0x28,
  I64__load = 0x29,
  F32__load = 0x2A,
  F64__load = 0x2B,
  I32__load8_s = 0x2C,
  I32__load8_u = 0x2D,
  I32__load16_s = 0x2E,
  I32__load16_u = 0x2F,
  I64__load8_s = 0x30,
  I64__load8_u = 0x31,
  I64__load16_s = 0x32,
  I64__load16_u = 0x33,
  I64__load32_s = 0x34,
  I64__load32_u = 0x35,
  I32__store = 0x36,
  I64__store = 0x37,
  F32__store = 0x38,
  F64__store = 0x39,
  I32__store8 = 0x3A,
  I32__store16 = 0x3B,
  I64__store8 = 0x3C,
  I64__store16 = 0x3D,
  I64__store32 = 0x3E,
  Memory__size = 0x3F,
  Memory__grow = 0x40,

  /// Const numeric instructions
  I32__const = 0x41,
  I64__const = 0x42,
  F32__const = 0x43,
  F64__const = 0x44,

  /// Numeric instructions
  I32__eqz = 0x45,
  I32__eq = 0x46,
  I32__ne = 0x47,
  I32__lt_s = 0x48,
  I32__lt_u = 0x49,
  I32__gt_s = 0x4A,
  I32__gt_u = 0x4B,
  I32__le_s = 0x4C,
  I32__le_u = 0x4D,
  I32__ge_s = 0x4E,
  I32__ge_u = 0x4F,
  I64__eqz = 0x50,
  I64__eq = 0x51,
  I64__ne = 0x52,
  I64__lt_s = 0x53,
  I64__lt_u = 0x54,
  I64__gt_s = 0x55,
  I64__gt_u = 0x56,
  I64__le_s = 0x57,
  I64__le_u = 0x58,
  I64__ge_s = 0x59,
  I64__ge_u = 0x5A,
  F32__eq = 0x5B,
  F32__ne = 0x5C,
  F32__lt = 0x5D,
  F32__gt = 0x5E,
  F32__le = 0x5F,
  F32__ge = 0x60,
  F64__eq = 0x61,
  F64__ne = 0x62,
  F64__lt = 0x63,
  F64__gt = 0x64,
  F64__le = 0x65,
  F64__ge = 0x66,
  I32__clz = 0x67,
  I32__ctz = 0x68,
  I32__popcnt = 0x69,
  I32__add = 0x6A,
  I32__sub = 0x6B,
  I32__mul = 0x6C,
  I32__div_s = 0x6D,
  I32__div_u = 0x6E,
  I32__rem_s = 0x6F,
  I32__rem_u = 0x70,
  I32__and = 0x71,
  I32__or = 0x72,
  I32__xor = 0x73,
  I32__shl = 0x74,
  I32__shr_s = 0x75,
  I32__shr_u = 0x76,
  I32__rotl = 0x77,
  I32__rotr = 0x78,
  I64__clz = 0x79,
  I64__ctz = 0x7a,
  I64__popcnt = 0x7b,
  I64__add = 0x7c,
  I64__sub = 0x7d,
  I64__mul = 0x7e,
  I64__div_s = 0x7f,
  I64__div_u = 0x80,
  I64__rem_s = 0x81,
  I64__rem_u = 0x82,
  I64__and = 0x83,
  I64__or = 0x84,
  I64__xor = 0x85,
  I64__shl = 0x86,
  I64__shr_s = 0x87,
  I64__shr_u = 0x88,
  I64__rotl = 0x89,
  I64__rotr = 0x8A,
  F32__abs = 0x8B,
  F32__neg = 0x8C,
  F32__ceil = 0x8D,
  F32__floor = 0x8E,
  F32__trunc = 0x8F,
  F32__nearest = 0x90,
  F32__sqrt = 0x91,
  F32__add = 0x92,
  F32__sub = 0x93,
  F32__mul = 0x94,
  F32__div = 0x95,
  F32__min = 0x96,
  F32__max = 0x97,
  F32__copysign = 0x98,
  F64__abs = 0x99,
  F64__neg = 0x9A,
  F64__ceil = 0x9B,
  F64__floor = 0x9C,
  F64__trunc = 0x9D,
  F64__nearest = 0x9E,
  F64__sqrt = 0x9F,
  F64__add = 0xA0,
  F64__sub = 0xA1,
  F64__mul = 0xA2,
  F64__div = 0xA3,
  F64__min = 0xA4,
  F64__max = 0xA5,
  F64__copysign = 0xA6,
  I32__wrap_i64 = 0xA7,
  I32__trunc_f32_s = 0xA8,
  I32__trunc_f32_u = 0xA9,
  I32__trunc_f64_s = 0xAA,
  I32__trunc_f64_u = 0xAB,
  I64__extend_i32_s = 0xAC,
  I64__extend_i32_u = 0xAD,
  I64__trunc_f32_s = 0xAE,
  I64__trunc_f32_u = 0xAF,
  I64__trunc_f64_s = 0xB0,
  I64__trunc_f64_u = 0xB1,
  F32__convert_i32_s = 0xB2,
  F32__convert_i32_u = 0xB3,
  F32__convert_i64_s = 0xB4,
  F32__convert_i64_u = 0xB5,
  F32__demote_f64 = 0xB6,
  F64__convert_i32_s = 0xB7,
  F64__convert_i32_u = 0xB8,
  F64__convert_i64_s = 0xB9,
  F64__convert_i64_u = 0xBA,
  F64__promote_f32 = 0xBB,
  I32__reinterpret_f32 = 0xBC,
  I64__reinterpret_f64 = 0xBD,
  F32__reinterpret_i32 = 0xBE,
  F64__reinterpret_i64 = 0xBF,
  I32__extend8_s = 0xC0,
  I32__extend16_s = 0xC1,
  I64__extend8_s = 0xC2,
  I64__extend16_s = 0xC3,
  I64__extend32_s = 0xC4,
  I32__trunc_sat_f32_s = 0xFC00,
  I32__trunc_sat_f32_u = 0xFC01,
  I32__trunc_sat_f64_s = 0xFC02,
  I32__trunc_sat_f64_u = 0xFC03,
  I64__trunc_sat_f32_s = 0xFC04,
  I64__trunc_sat_f32_u = 0xFC05,
  I64__trunc_sat_f64_s = 0xFC06,
  I64__trunc_sat_f64_u = 0xFC07
};

/// Instruction opcode enumeration string mapping.
static inline std::unordered_map<OpCode, std::string> OpCodeStr = {
    /// Control instructions
    {OpCode::Unreachable, "unreachable"},
    {OpCode::Nop, "nop"},
    {OpCode::Block, "block"},
    {OpCode::Loop, "loop"},
    {OpCode::If, "if"},
    {OpCode::Else, "else"},
    {OpCode::End, "end"},
    {OpCode::Br, "br"},
    {OpCode::Br_if, "br_if"},
    {OpCode::Br_table, "br_table"},
    {OpCode::Return, "return"},
    {OpCode::Call, "call"},
    {OpCode::Call_indirect, "call_indirect"},

    /// Parametric Instructions
    {OpCode::Drop, "drop"},
    {OpCode::Select, "select"},

    /// Variable Instructions
    {OpCode::Local__get, "local.get"},
    {OpCode::Local__set, "local.set"},
    {OpCode::Local__tee, "local.tee"},
    {OpCode::Global__get, "global.get"},
    {OpCode::Global__set, "global.set"},

    /// Memory Instructions
    {OpCode::I32__load, "i32.load"},
    {OpCode::I64__load, "i64.load"},
    {OpCode::F32__load, "f32.load"},
    {OpCode::F64__load, "f64.load"},
    {OpCode::I32__load8_s, "i32.load8_s"},
    {OpCode::I32__load8_u, "i32.load8_u"},
    {OpCode::I32__load16_s, "i32.load16_s"},
    {OpCode::I32__load16_u, "i32.load16_u"},
    {OpCode::I64__load8_s, "i64.load8_s"},
    {OpCode::I64__load8_u, "i64.load8_u"},
    {OpCode::I64__load16_s, "i64.load16_s"},
    {OpCode::I64__load16_u, "i64.load16_u"},
    {OpCode::I64__load32_s, "i64.load32_s"},
    {OpCode::I64__load32_u, "i64.load32_u"},
    {OpCode::I32__store, "i32.store"},
    {OpCode::I64__store, "i64.store"},
    {OpCode::F32__store, "f32.store"},
    {OpCode::F64__store, "f64.store"},
    {OpCode::I32__store8, "i32.store8"},
    {OpCode::I32__store16, "i32.store16"},
    {OpCode::I64__store8, "i64.store8"},
    {OpCode::I64__store16, "i64.store16"},
    {OpCode::I64__store32, "i64.store32"},
    {OpCode::Memory__size, "memory.size"},
    {OpCode::Memory__grow, "memory.grow"},

    /// Const numeric instructions
    {OpCode::I32__const, "i32.const"},
    {OpCode::I64__const, "i64.const"},
    {OpCode::F32__const, "f32.const"},
    {OpCode::F64__const, "f64.const"},

    /// Numeric instructions
    {OpCode::I32__eqz, "i32.eqz"},
    {OpCode::I32__eq, "i32.eq"},
    {OpCode::I32__ne, "i32.ne"},
    {OpCode::I32__lt_s, "i32.lt_s"},
    {OpCode::I32__lt_u, "i32.lt_u"},
    {OpCode::I32__gt_s, "i32.gt_s"},
    {OpCode::I32__gt_u, "i32.gt_u"},
    {OpCode::I32__le_s, "i32.le_s"},
    {OpCode::I32__le_u, "i32.le_u"},
    {OpCode::I32__ge_s, "i32.ge_s"},
    {OpCode::I32__ge_u, "i32.ge_u"},
    {OpCode::I64__eqz, "i64.eqz"},
    {OpCode::I64__eq, "i64.eq"},
    {OpCode::I64__ne, "i64.ne"},
    {OpCode::I64__lt_s, "i64.lt_s"},
    {OpCode::I64__lt_u, "i64.lt_u"},
    {OpCode::I64__gt_s, "i64.gt_s"},
    {OpCode::I64__gt_u, "i64.gt_u"},
    {OpCode::I64__le_s, "i64.le_s"},
    {OpCode::I64__le_u, "i64.le_u"},
    {OpCode::I64__ge_s, "i64.ge_s"},
    {OpCode::I64__ge_u, "i64.ge_u"},
    {OpCode::F32__eq, "f32.eq"},
    {OpCode::F32__ne, "f32.ne"},
    {OpCode::F32__lt, "f32.lt"},
    {OpCode::F32__gt, "f32.gt"},
    {OpCode::F32__le, "f32.le"},
    {OpCode::F32__ge, "f32.ge"},
    {OpCode::F64__eq, "f64.eq"},
    {OpCode::F64__ne, "f64.ne"},
    {OpCode::F64__lt, "f64.lt"},
    {OpCode::F64__gt, "f64.gt"},
    {OpCode::F64__le, "f64.le"},
    {OpCode::F64__ge, "f64.ge"},
    {OpCode::I32__clz, "i32.clz"},
    {OpCode::I32__ctz, "i32.ctz"},
    {OpCode::I32__popcnt, "i32.popcnt"},
    {OpCode::I32__add, "i32.add"},
    {OpCode::I32__sub, "i32.sub"},
    {OpCode::I32__mul, "i32.mul"},
    {OpCode::I32__div_s, "i32.div_s"},
    {OpCode::I32__div_u, "i32.div_u"},
    {OpCode::I32__rem_s, "i32.rem_s"},
    {OpCode::I32__rem_u, "i32.rem_u"},
    {OpCode::I32__and, "i32.and"},
    {OpCode::I32__or, "i32.or"},
    {OpCode::I32__xor, "i32.xor"},
    {OpCode::I32__shl, "i32.shl"},
    {OpCode::I32__shr_s, "i32.shr_s"},
    {OpCode::I32__shr_u, "i32.shr_u"},
    {OpCode::I32__rotl, "i32.rotl"},
    {OpCode::I32__rotr, "i32.rotr"},
    {OpCode::I64__clz, "i64.clz"},
    {OpCode::I64__ctz, "i64.ctz"},
    {OpCode::I64__popcnt, "i64.popcnt"},
    {OpCode::I64__add, "i64.add"},
    {OpCode::I64__sub, "i64.sub"},
    {OpCode::I64__mul, "i64.mul"},
    {OpCode::I64__div_s, "i64.div_s"},
    {OpCode::I64__div_u, "i64.div_u"},
    {OpCode::I64__rem_s, "i64.rem_s"},
    {OpCode::I64__rem_u, "i64.rem_u"},
    {OpCode::I64__and, "i64.and"},
    {OpCode::I64__or, "i64.or"},
    {OpCode::I64__xor, "i64.xor"},
    {OpCode::I64__shl, "i64.shl"},
    {OpCode::I64__shr_s, "i64.shr_s"},
    {OpCode::I64__shr_u, "i64.shr_u"},
    {OpCode::I64__rotl, "i64.rotl"},
    {OpCode::I64__rotr, "i64.rotr"},
    {OpCode::F32__abs, "f32.abs"},
    {OpCode::F32__neg, "f32.neg"},
    {OpCode::F32__ceil, "f32.ceil"},
    {OpCode::F32__floor, "f32.floor"},
    {OpCode::F32__trunc, "f32.trunc"},
    {OpCode::F32__nearest, "f32.nearest"},
    {OpCode::F32__sqrt, "f32.sqrt"},
    {OpCode::F32__sub, "f32.sub"},
    {OpCode::F32__mul, "f32.mul"},
    {OpCode::F32__div, "f32.div"},
    {OpCode::F32__min, "f32.min"},
    {OpCode::F32__max, "f32.max"},
    {OpCode::F32__copysign, "f32.copysign"},
    {OpCode::F64__abs, "f64.abs"},
    {OpCode::F64__neg, "f64.neg"},
    {OpCode::F64__ceil, "f64.ceil"},
    {OpCode::F64__floor, "f64.floor"},
    {OpCode::F64__trunc, "f64.trunc"},
    {OpCode::F64__nearest, "f64.nearest"},
    {OpCode::F64__sqrt, "f64.sqrt"},
    {OpCode::F64__sub, "f64.sub"},
    {OpCode::F64__mul, "f64.mul"},
    {OpCode::F64__div, "f64.div"},
    {OpCode::F64__min, "f64.min"},
    {OpCode::F64__max, "f64.max"},
    {OpCode::F64__copysign, "f64.copysign"},
    {OpCode::I32__wrap_i64, "i32.wrap_i64"},
    {OpCode::I32__trunc_f32_s, "i32.trunc_f32_s"},
    {OpCode::I32__trunc_f32_u, "i32.trunc_f32_u"},
    {OpCode::I32__trunc_f64_s, "i32.trunc_f64_s"},
    {OpCode::I32__trunc_f64_u, "i32.trunc_f64_u"},
    {OpCode::I64__extend_i32_s, "i64.extend_i32_s"},
    {OpCode::I64__extend_i32_u, "i64.extend_i32_u"},
    {OpCode::I64__trunc_f32_s, "i64.trunc_f32_s"},
    {OpCode::I64__trunc_f32_u, "i64.trunc_f32_u"},
    {OpCode::I64__trunc_f64_s, "i64.trunc_f64_s"},
    {OpCode::I64__trunc_f64_u, "i64.trunc_f64_u"},
    {OpCode::F32__convert_i32_s, "f32.convert_i32_s"},
    {OpCode::F32__convert_i32_u, "f32.convert_i32_u"},
    {OpCode::F32__convert_i64_s, "f32.convert_i64_s"},
    {OpCode::F32__convert_i64_u, "f32.convert_i64_u"},
    {OpCode::F32__demote_f64, "f32.demote_f64"},
    {OpCode::F64__convert_i32_s, "f64.convert_i32_s"},
    {OpCode::F64__convert_i32_u, "f64.convert_i32_u"},
    {OpCode::F64__convert_i64_s, "f64.convert_i64_s"},
    {OpCode::F64__convert_i64_u, "f64.convert_i64_u"},
    {OpCode::F64__promote_f32, "f64.promote_f32"},
    {OpCode::I32__reinterpret_f32, "i32.reinterpret_f32"},
    {OpCode::I64__reinterpret_f64, "i64.reinterpret_f64"},
    {OpCode::F32__reinterpret_i32, "f32.reinterpret_i32"},
    {OpCode::F64__reinterpret_i64, "f64.reinterpret_i64"},
    {OpCode::I32__extend8_s, "i32.extend8_s"},
    {OpCode::I32__extend16_s, "i32.extend16_s"},
    {OpCode::I64__extend8_s, "i64.extend8_s"},
    {OpCode::I64__extend16_s, "i64.extend16_s"},
    {OpCode::I64__extend32_s, "i64.extend32_s"},
    {OpCode::I32__trunc_sat_f32_s, "i32.trunc_sat_f32_s"},
    {OpCode::I32__trunc_sat_f32_u, "i32.trunc_sat_f32_u"},
    {OpCode::I32__trunc_sat_f64_s, "i32.trunc_sat_f64_s"},
    {OpCode::I32__trunc_sat_f64_u, "i32.trunc_sat_f64_u"},
    {OpCode::I64__trunc_sat_f32_s, "i64.trunc_sat_f32_s"},
    {OpCode::I64__trunc_sat_f32_u, "i64.trunc_sat_f32_u"},
    {OpCode::I64__trunc_sat_f64_s, "i64.trunc_sat_f64_s"},
    {OpCode::I64__trunc_sat_f64_u, "i64.trunc_sat_f64_u"}};

} // namespace SSVM
